import { EMPTY, Expression } from './types';
import { parse } from './parser';
import _ from 'lodash';
import { union } from './union';
import { intersection } from './intersection';
import { diff } from './diff';
import { print } from './print';
import { reverse } from './not';

type MayBeExp = string | ExpressionIns | Expression;

/**
 * 提供更友善的操作接口
 */
const hop = Object.prototype.hasOwnProperty;
function isExpressionIns(ins: MayBeExp): ins is ExpressionIns {
  return hop.call(ins, 'exp');
}

export class ExpressionIns {
  private exp: Expression = EMPTY;

  constructor(exp: MayBeExp) {
    this.exp = this.anyToExpression(exp);
  }

  anyToExpression(exp: MayBeExp): Expression {
    if (typeof exp === 'string') {
      return parse(exp);
    } else if (isExpressionIns(exp)) {
      return _.clone(exp.exp);
    }

    return exp;
  }

  // 交
  intersection(exp: MayBeExp): ExpressionIns {
    const expIns = this.anyToExpression(exp);
    const rstExp = intersection(this.exp, expIns);
    return new ExpressionIns(rstExp);
  }

  // 并
  union(exp: MayBeExp): ExpressionIns {
    const expIns = this.anyToExpression(exp);
    const rstExp = union(this.exp, expIns);
    return new ExpressionIns(rstExp);
  }

  // 差
  diff(exp: MayBeExp): ExpressionIns {
    const expIns = this.anyToExpression(exp);
    const rstExp = diff(this.exp, expIns);
    return new ExpressionIns(rstExp);
  }

  // 取反
  not(): ExpressionIns {
    const rstExp = reverse(this.exp);
    return new ExpressionIns(rstExp);
  }

  toString(): string {
    return print(this.exp);
  }
}
